﻿using UnityEngine;
using System.Collections;

public class PlayerMovement : MonoBehaviour {

	// Einstellungen des Spielers (Werte werden durch Editor überschrieben!)
	public float movementSpeedForward = 5;
	public float movementSpeedBackward = 2;
	public float rotationSpeed = 100;
	public float jumpForce = 4;

	public GameObject sword;
	public GameObject chest;
	public GameObject rightHand;

	// Komponenten
	private Animator anim;
	private Rigidbody rBody;

	private bool startJump;
	private float curMovementSpeed;
	private float curRotationSpeed;

	private bool isSwordPulled;

	// Variablen für GroundCheck
	private int groundCheckLayer;
	private float groundCheckRadius;
	private Vector3 groundCheckOffset;
	private bool isGrounded;

	/// <summary>
	/// Einstiegspunkt des Skripts. Wird einmalig ausgeführt sobald Skript der Szene hinzugefügt wird.
	/// </summary>
	void Start() {
	
		// Komponenten initialisieren
		anim = gameObject.GetComponent<Animator> ();
		rBody = gameObject.GetComponent<Rigidbody> ();

		// GroundCheck-Einstellungen
		groundCheckLayer = 1 << 8;
		groundCheckRadius = 0.3f;
		groundCheckOffset = new Vector3 (0, 0.15f, 0);

		// GroundCheck durchführen
		isGrounded = doGroundCheck ();

		// selbständige Rotationen des Rigidbodies sperren
		rBody.constraints = RigidbodyConstraints.FreezeRotationX | RigidbodyConstraints.FreezeRotationY | RigidbodyConstraints.FreezeRotationZ;
	}

	/// <summary>
	/// Update - Wird einmal pro Frame aufgerufen. Sinnvoll für Abfragen von Nutzereingaben.
	/// </summary>
	void Update() {

		// befindet sich der Spieler gerade auf dem Boden?
		isGrounded = doGroundCheck ();

		// setze Status (am Boden/in der Luft) in der Animator-StateMachine
		anim.SetBool ("isGrounded", isGrounded);

		if (isGrounded) {

			// Beginne Animation: vorwärts laufen
			if (Input.GetKeyDown (KeyCode.UpArrow)) {
				curMovementSpeed = movementSpeedForward;
				anim.SetBool ("isRunning", true);
			}

			// Beginne Animation: rückwärts laufen
			if (Input.GetKeyDown (KeyCode.DownArrow)) {
				curMovementSpeed = -movementSpeedBackward;
				anim.SetBool ("isWalking", true);
			}

			// Spieler drehen
			if (Input.GetKey (KeyCode.LeftArrow)) 		// links
				curRotationSpeed = -rotationSpeed;
			else if (Input.GetKey (KeyCode.RightArrow))	// rechts
				curRotationSpeed = rotationSpeed;
			else 										// nicht drehen				
				curRotationSpeed = 0;

			// Sprung triggern, wenn Pfeiltaste + Alt gedrückt und gerade keine Sprung-Animation ausgeführt wird
			if (Input.GetKeyDown (KeyCode.LeftAlt) && 
				Input.GetKey (KeyCode.UpArrow) && 
				!anim.GetCurrentAnimatorStateInfo (0).IsName ("JumpForward")) {

				anim.SetTrigger ("jumpForward");
				startJump = true;
			}

			if (Input.GetKeyDown (KeyCode.Space))
				anim.SetTrigger ("pullSword");
		}

		// Beende Animation: vorwärts laufen
		if (Input.GetKeyUp (KeyCode.UpArrow))
			anim.SetBool ("isRunning", false);

		// Beende Animation: rückwärts laufen
		if (Input.GetKeyUp (KeyCode.DownArrow))
			anim.SetBool ("isWalking", false);

		handleSword ();
	}

	/// <summary>
	/// FixedUpdate - Wird einmal pro Fixed-Framerate (einstellbar im Editor) aufgerufen. Sinnvoll für Berechnungen der PhysicEngine.
	/// </summary>
	void FixedUpdate () {

		if (isGrounded) {

			// Spieler nach vorn bewegen
			if (anim.GetBool ("isRunning"))
				rBody.MovePosition (rBody.position + transform.forward * curMovementSpeed * Time.deltaTime);

			// Spieler nach hinten bewegen
			if (anim.GetBool ("isWalking")) {
				rBody.MovePosition (rBody.position + transform.forward * curMovementSpeed * Time.deltaTime);
			}

			// Spieler drehen
			rBody.MoveRotation (Quaternion.Euler (rBody.rotation.eulerAngles + new Vector3 (0, curRotationSpeed, 0) * Time.deltaTime));

			// Sprung ausführen
			if (startJump) {

				// bisherige Sprungkraft resetten
				// verhindert immer schneller springenden Spieler, wenn Sprung schnell hintereinander getriggert
				rBody.velocity = Vector3.zero;
				rBody.angularVelocity = Vector3.zero; 

				// Kraft für neuen Sprung hinzufügen
				rBody.AddForce ((Vector3.up + transform.forward) * jumpForce, ForceMode.Impulse);

				// sicherstellen das Sprung nur einmalig getriggert wird
				startJump = false;
			}
		}
	}

	/// <summary>
	/// Methode zum Überprüfen, ob sich der Spieler aktuell auf dem Boden oder in der Luft aufhält 
	/// </summary>
	/// <returns><c>true</c>, Spieler am Boden, <c>false</c> Spieler in der Luft.</returns>
	private bool doGroundCheck() {

		return Physics.CheckSphere (transform.position + groundCheckOffset, groundCheckRadius, groundCheckLayer);
	}

	private void handleSword() {
	

		if (!isSwordPulled && anim.GetCurrentAnimatorStateInfo (1).IsName ("PullSword") && anim.GetCurrentAnimatorStateInfo (1).normalizedTime < 0.2f) {
			anim.SetLayerWeight (1, 1);
		}

		if (!isSwordPulled && anim.GetCurrentAnimatorStateInfo (1).IsName ("PullSword") && anim.GetCurrentAnimatorStateInfo (1).normalizedTime > 0.5f) {

			isSwordPulled = true;
			sword.transform.parent = rightHand.transform;
			sword.transform.localPosition = new Vector3 (-0.081f, -0.028f, 0.013f);
			sword.transform.localRotation = Quaternion.Euler (-51.739f, 393.09f, -201.587f);
		}

		if (isSwordPulled && anim.GetCurrentAnimatorStateInfo (1).IsName ("PullSwordBack") && anim.GetCurrentAnimatorStateInfo (1).normalizedTime > 0.5f) {

			isSwordPulled = false;
			sword.transform.parent = chest.transform;
			sword.transform.localPosition = new Vector3 (-0.293f, 0.089f, 0.136f);
			sword.transform.localRotation = Quaternion.Euler (-1.388f, -1.038f, 74.922f);
		}
		else if (!isSwordPulled && anim.GetCurrentAnimatorStateInfo (1).IsName ("PullSwordBack") && anim.GetCurrentAnimatorStateInfo (1).normalizedTime > 0.5f && anim.GetCurrentAnimatorStateInfo (1).normalizedTime < 1.1f) {

			anim.SetLayerWeight (1, Mathf.Lerp(1, 0, Mathf.Clamp01(anim.GetCurrentAnimatorStateInfo (1).normalizedTime)));
		}
	}

	/*void OnDrawGizmos() {
	
		Gizmos.DrawWireSphere (transform.position + new Vector3 (0, 0.15f, 0), 0.3f);
	}*/
}